package qmlt.learning.knn;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import qmlt.dataset.Attribute;
import qmlt.dataset.DataSet;
import qmlt.dataset.Instance;
import qmlt.learning.knn.control.KNNController;

public class NTGrowthKNN extends KNN
{
	protected int										total;

	protected Map<Object, Integer>	nPosSamples	= new HashMap<Object, Integer>();

	protected List<Item>					predictingItems;
	
	@Override
	public void feedAnInstance(Instance inst)
	{
		// true class
		Object target = inst.getTarget();
		if (nPosSamples.containsKey(target))
		{
			nPosSamples.put(target, nPosSamples.get(target) + 1);
		}
		else
		{
			nPosSamples.put(target, 1);
		}
		total++;

		if (items.size() < controller.getK())
		{
			super.feedAnInstance(inst);
			return;
		}
		
		// predict
		Object pred = predict(inst);
		int k = controller.getK();
		predictingItems = items.subList(0, k);

		// if incorrect, record
		if (!pred.equals(inst.getTarget()))
		{
			super.feedAnInstance(inst);
		}

		// update predicting sample records
		for (Item item : predictingItems)
		{
			Object itemRst = item.instance.getTarget();
			if (itemRst.equals(pred))
			{
				item.correct++;
			}
			else
			{
				item.incorrect++;
			}

			// check for very bad sample records
			float r = (float) nPosSamples.get(itemRst) / total;
			float r1 = (float) item.correct / (item.correct + item.incorrect);
			float std = r * (1 - r) / total;
			if (r1 < r - std * 1.28) // 1.28 = z(0.9)
				items.remove(item);
		}
	}

	@Override
	public void train(DataSet trainSet, KNNController controller)
	{
		assert trainSet.getTargetDef().type.equals(Attribute.STRING) : "NTGrowth algorithm applies to classification problems only.";

		super.train(trainSet, controller);
		System.out.println("retrained samples: " + items.size());
	}
}
